#include <EB0/EB0.h>

namespace EB0
{
namespace Entities
{
#pragma region Constructor / Destructor
	// Constructor
	SeekBot::SeekBot() // Calls Entity::Entity()
	{
		// Create an image for the SeekBot
		mSeekBotImage = Managers::ImageManager::getSingletonPtr()->createImage("graphics/title-mystes-2.png");

		// Create a sprite which will use the image
		mSeekBotSprite = new sf::Sprite(*mSeekBotImage);
		mSeekBotSprite->SetCenter(mSeekBotSprite->GetSize().x / 2.0f, mSeekBotSprite->GetSize().y / 2.0f); // centered origin
	}

	// Destructor
	SeekBot::~SeekBot() // Calls Entity::~Entity()
	{
		// Delete sprite
		if (mSeekBotSprite)
		{
			delete mSeekBotSprite;
			mSeekBotSprite = 0;
		}

		// Delete image
		if (mSeekBotImage)
			Managers::ImageManager::getSingletonPtr()->destroyImage(mSeekBotImage);
	}
#pragma endregion

#pragma region Attach / Remove
	// Called whenever the entity is attached to a world
	// Used mostly for creating the body
	void SeekBot::onAttach(States::World* worldState)
	{
		// Define the body
		mBodyDef = new b2BodyDef;
		mBodyDef->position.SetZero();

		// Define body shape
		b2PolygonDef shapeDef;
		
		if (mSeekBotImage)
			shapeDef.SetAsBox((float32)(mSeekBotImage->GetWidth() / TILE_SIZE / 2), (float32)(mSeekBotImage->GetHeight() / TILE_SIZE / 2));
		else
			shapeDef.SetAsBox(1.0f, 1.0f);

		shapeDef.density = 1.0f;
		shapeDef.friction = 0.3f;

		// Create the body
		mBody = worldState->getWorld()->CreateBody(mBodyDef);
		mBody->CreateShape(&shapeDef);
		mBody->SetMassFromShapes();
	}

	// Called whenever the entity is removed from a world
	// Used mostly for destroying the body
	void SeekBot::onRemove(States::World* worldState)
	{
		// Destroy the body
		if (mBody)
		{
			worldState->getWorld()->DestroyBody(mBody);
			mBody = 0;
		}

		// Destroy the body definition
		if (mBodyDef)
		{
			delete mBodyDef;
			mBodyDef = 0;
		}
	}
#pragma endregion

#pragma region Step
	// Step function called for purposes such as AI
	// A pointer to the world state is passed in to access other objects
	void SeekBot::step(States::World* worldState, float dt)
	{
		// Place a cap on the SeekBot's speed since we're using impulses
		// We'll normalize the SeekBot speed to TILE_SIZE
		if (mBody)
		{
			// Variables
			b2Vec2 direction;
			b2Vec2 desiredVelocity;
			b2Vec2 resultVelocity;
			float dirMag;

			// Seek the "Player"
			Entities::Entity* playerEntity = worldState->fetchEntity("Player");

			if (playerEntity)
			{
				direction = playerEntity->getBody()->GetPosition() - mBody->GetPosition();
				dirMag = direction.Length();
				direction.x /= dirMag;
				direction.y /= dirMag;
			}

			// Get the desired velocity
			desiredVelocity.x = direction.x * TILE_SIZE * 8; // 8 tiles per second max
			desiredVelocity.y = direction.y * TILE_SIZE * 8;

			// Calculate the force to add
			resultVelocity.x = desiredVelocity.x - mBody->GetLinearVelocity().x;
			resultVelocity.y = desiredVelocity.y - mBody->GetLinearVelocity().y;

			// Apply the force
			mBody->ApplyForce(resultVelocity, mBody->GetWorldCenter());

			// Disallow rotation
			mBody->SetAngularVelocity(0);
			mBody->SetXForm(mBody->GetWorldCenter(), 0);
		}
	}
#pragma endregion

#pragma region Render
	// Render
	void SeekBot::Render(sf::RenderTarget& Target) const
	{
		Target.Draw(*mSeekBotSprite);
	}
#pragma endregion
} // namespace Entities
}